/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
package com.googlecode.ivybeans.module.classpath;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.netbeans.api.java.classpath.ClassPath;

import org.netbeans.api.java.project.JavaProjectConstants;
import org.netbeans.api.java.queries.UnitTestForSourceQuery;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.spi.java.classpath.ClassPathFactory;
import org.netbeans.spi.java.classpath.ClassPathProvider;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;

/**
 * 
 * @author lforet
 */
public class ClassPathProviderImpl implements ClassPathProvider {

    private static enum FileType {

        SOURCE, TEST_SOURCE, UNKNOWN
    };
    private final Project project;
    private List<FileObject> sourceRoots;
    private List<FileObject> testSourceRoots;
    private Map<ClassPathScope, ClassPath> cache = new HashMap<ClassPathScope, ClassPath>();

    public ClassPathProviderImpl(Project project) {
        this.project = project;
    }

    public ClassPath findClassPath(FileObject fileObject, String type) {
        switch (getFileType(fileObject)) {
            case SOURCE: {
                if (ClassPathScope.COMPILE.getType().equals(type)) {
                    return getClassPath(ClassPathScope.COMPILE);
                } else if (ClassPathScope.RUNTIME.getType().equals(type)) {
                    return getClassPath(ClassPathScope.RUNTIME);
                }
                break;
            }
            case TEST_SOURCE: {
                if (ClassPathScope.COMPILE.getType().equals(type)) {
                    return getClassPath(ClassPathScope.COMPILE_TEST);
                } else if (ClassPathScope.RUNTIME.getType().equals(type)) {
                    return getClassPath(ClassPathScope.RUNTIME_TEST);
                }
            }
        }
        return null;
    }

    public synchronized ClassPath getClassPath(ClassPathScope scope) {
        ClassPath cp = cache.get(scope);
        if (cp == null) {
            cp = ClassPathFactory.createClassPath(new ScopedClassPathImpl(project, scope));
            cache.put(scope, cp);
        }
        return cp;
    }

    private FileType getFileType(FileObject fo) {

        if (sourceRoots == null) {
            SourceGroup[] allJavaSources = ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
            sourceRoots = new ArrayList<FileObject>();
            testSourceRoots = new ArrayList<FileObject>();
            for (SourceGroup sourceGroup : allJavaSources) {
                FileObject sourceFO = sourceGroup.getRootFolder();
                if (UnitTestForSourceQuery.findSources(sourceFO).length > 0) {
                    testSourceRoots.add(sourceFO);
                } else {
                    sourceRoots.add(sourceFO);
                }
            }
        }

        for (FileObject sourceFO : sourceRoots) {
            if (FileUtil.isParentOf(sourceFO, fo)) {
                return FileType.SOURCE;
            }
        }
        for (FileObject testSourceFO : testSourceRoots) {
            if (FileUtil.isParentOf(testSourceFO, fo)) {
                return FileType.TEST_SOURCE;
            }
        }
        return FileType.UNKNOWN;
    }
}
